﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KinConquer.Entities
{
    public class Hero : Entity//, IDisposable
    {
        public KinSocket.Connection Owner { get; private set; }

        public Queue<QdAction> ActionQueue { get; private set; }

        public Screen Screen;
        public TimeStamps TimeStamps = new TimeStamps();

        //private Boolean DisposeInvoked = false;

        public Hero(KinSocket.Connection Client)
            : base(ObjectType.Hero | ObjectType.Entity)
        {
            Owner = Client;
            Identifier = Owner.Identifier;
            ActionQueue = new Queue<QdAction>();
            Screen = new Screen(this);
        }
        //~Hero() { Dispose(); }

        public UInt32 Gold
        {
            get { return mGold; }
            set { mGold = value; Update("money", mGold); }
        }
        public UInt32 CP
        {
            get { return mCP; }
            set { mCP = value; Update("cp", mCP); }
        }
        public UInt32 CPB
        {
            get { return mCPB; }
            set { mCPB = value; Update("cpb", mCPB); }
        }
        public UInt32 MaxHitPoints
        {
            get { return mMaxHitPoints; }
            set { mMaxHitPoints = value; }
        }
        public UInt32 MaxManaPoints
        {
            get { return mMaxManaPoints; }
            set { mMaxManaPoints = value; }
        }
        public UInt32 ManaPoints
        {
            get { return mManaPoints; }
            set { mManaPoints = value; Update("manapoints", mManaPoints); }
        }
        public UInt16 Strength
        {
            get { return mStr; }
            set { mStr = value; Update("strength", mStr); }
        }
        public UInt16 Vitality
        {
            get { return mVit; }
            set { mVit = value; Update("vitality", mVit); }
        }
        public UInt16 Spirit
        {
            get { return mSpi; }
            set { mSpi = value; Update("spirit", mSpi); }
        }
        public UInt16 Agility
        {
            get { return mAgi; }
            set { mAgi = value; Update("agility", mAgi); }
        }
        public UInt16 StatPoints
        {
            get { return mStatPoints; }
            set { mStatPoints = value; Update("statpoints", mStatPoints); }
        }
        public UInt16 PKPoints
        {
            get { return mPkPoints; }
            set { mPkPoints = value; Update("pkpoints", mPkPoints); }
        }
        public UInt64 Experience
        {
            get { return mExp; }
            set { mExp = value; Update("exp", mExp); }
        }

        public PKMode PKMode
        {
            get { return mPKMode; }
            set { mPKMode = value; }
        }

        public void Update(String col, Object val)
        {
            Program.Database.ExecuteNonQuery("UPDATE hero SET " + col + " = '" + val.ToString() + "' WHERE id = " + Identifier);
        }

        public void Teleport(UInt32 Map, UInt16 X, UInt16 Y, UInt32 DMap = 0)
        {

        }

        public void PullBack(UInt16 x, UInt16 y)
        {

        }

        public Boolean DoneJumping
        {
            get
            {
                return KinSocket.Native.TIME.Now.Time > TimeStamps.LastJump.AddMilliseconds(TimeStamps.LastJumpSpeed).Time;
            }
        }

        public Boolean Load()
        {
            MySql.Data.MySqlClient.MySqlDataReader Reader = null;
            Program.Database.ExecuteReader("SELECT * FROM hero WHERE id = " + Identifier, ref Reader);
            if (Reader != null)
            {
                if (Reader.Read())
                {
                    String name = Reader["name"].ToString() + (Owner.Type != KinSocket.Connection.Types.Player ? "[" + Owner.Type + "]" : "");

                    Byte[] tmp = new Byte[SpawnPacket.Length];
                    SpawnPacket.CopyTo(tmp, 0);
                    SpawnPacket = new Byte[tmp.Length + name.Length];
                    Buffer.BlockCopy(tmp, 0, SpawnPacket, 0, tmp.Length);
                    KinSocket.PacketConstructor.Write((UInt16)SpawnPacket.Length, 0, SpawnPacket);

                    Name = name;
                    UInt32 TransType = Convert.ToUInt32(Reader["transtype"]);
                    UInt32 Avatar = Convert.ToUInt32(Reader["avatar"]);
                    UInt32 Body = Convert.ToUInt32(Reader["body"]);
                    Lookface = (UInt32)((TransType * 10000000) + Avatar * 10000 + Body);
                    Reborn = Convert.ToByte(Reader["reborn"]);
                    FirstClass = Convert.ToByte(Reader["firstclass"]);
                    SecondClass = Convert.ToByte(Reader["secondclass"]);
                    ThirdClass = Convert.ToByte(Reader["thirdclass"]);
                    Level = Convert.ToByte(Reader["level"]);
                    X = Convert.ToUInt16(Reader["x"]);
                    Y = Convert.ToUInt16(Reader["y"]);
                    Map = Convert.ToUInt16(Reader["mapid"]);
                    DMap = Convert.ToUInt16(Reader["dmapid"]);
                    HitPoints = Convert.ToUInt32(Reader["hitpoints"]);

                    Strength = Convert.ToUInt16(Reader["strength"]);
                    Agility = Convert.ToUInt16(Reader["agility"]);
                    Vitality = Convert.ToUInt16(Reader["vitality"]);
                    Spirit = Convert.ToUInt16(Reader["spirit"]);
                    StatPoints = Convert.ToUInt16(Reader["statpoints"]);
                    PKPoints = Convert.ToUInt16(Reader["pkpoints"]);
                    ManaPoints = Convert.ToUInt32(Reader["manapoints"]);
                    Gold = Convert.ToUInt32(Reader["money"]);
                    CP = Convert.ToUInt32(Reader["cp"]);
                    CPB = Convert.ToUInt32(Reader["cpb"]);
                    Experience = Convert.ToUInt64(Reader["exp"]);

                    Reader.Close();
                    return true;
                }
                else
                {
                    Reader.Close();
                    return false;
                }
            }
            else return false;
        }

        public void EnqeueAction(QdAction a)
        {
            ActionQueue.Enqueue(a);
        }

        public static Boolean GetStats(UInt16 job, Byte level, ref UInt16 str, ref UInt16 vit, ref UInt16 spi, ref UInt16 agi)
        {
            job = (UInt16)((job / 10) * 10);
            MySql.Data.MySqlClient.MySqlDataReader reader = null;
            Program.Database.ExecuteReader("SELECT * FROM stats WHERE Class = " + job + " AND Level = " + level, ref reader);
            if (reader != null)
            {
                if (reader.Read())
                {
                    str = Convert.ToUInt16(reader["Strength"]);
                    vit = Convert.ToUInt16(reader["Vitality"]);
                    spi = Convert.ToUInt16(reader["Spirit"]);
                    agi = Convert.ToUInt16(reader["Dexterity"]);
                    return true;
                }
            }
            return false;
        }
        public static Int32 GetJumpTime(UInt16 x, UInt16 y, UInt16 newX, UInt16 newY)
        {
            return 0;
        }

        private UInt16
            mStr, mSpi, mAgi, mVit, mStatPoints,
            mPkPoints;
        private UInt32
            mMaxHitPoints,
            mMaxManaPoints,
            mManaPoints,
            mGold,
            mCP,
            mCPB;
        private UInt64
            mExp;
        private PKMode mPKMode;

        /*public void Dispose()
        {
            if (!DisposeInvoked)
            {
                DisposeInvoked = true;
                Program.HeroPool.Remove(Identifier);
                GC.SuppressFinalize(this);
            }
        }*/
    }

    public unsafe class QdAction
    {
        public QdActionType Type;
        public Byte[] Data;
        public Boolean Bool = false;
        public Int32 Int = 0;
        public UInt16 X, Y;

        public QdAction() { }
        public QdAction(QdActionType t)
        {
            Type = t;
        }
        public QdAction(QdActionType t, Byte[] d, Boolean bo = false)
        {
            Type = t;
            Data = new Byte[d.Length];
            d.CopyTo(Data, 0);
            Bool = bo;
        }
        public QdAction(QdActionType t, Byte* d, Boolean bo = false)
        {
            Type = t;
            Byte[] b = KinSocket.PacketConstructor.PointerToArray(d);
            Data = new Byte[b.Length];
            b.CopyTo(Data, 0);
            Bool = bo;
        }
        public QdAction(QdActionType t, void* d, Boolean bo = false)
        {
            Type = t;
            IntPtr intp = new IntPtr(d);
            Byte* data = (Byte*)intp;
            Byte[] b = KinSocket.PacketConstructor.PointerToArray(data);
            Data = new Byte[b.Length];
            b.CopyTo(Data, 0);
            Bool = bo;
        }
    }

    public enum QdActionType
    {
        SendRangePacket,
        SendScreenPacket,
        UpdateScreen,
        CleanUpScreen,
        UpdateCleanScreen,
        GetSurroundings,
    }

    public enum PKMode : byte
    {
        Kill = 0x00,
        Peace = 0x01,
        Team = 0x02,
        Capture = 0x03
    }
}
